Imports System
Imports ValidationFramework
Imports ValidationFramework.Reflection


Namespace NewRule
    Public Class RequiredCharacterRule
        Inherits Rule
        ' Methods


        ''' <summary>
        ''' Initialize a new instance of the <see cref="RequiredCharacterRule"/> class.
        ''' </summary>
        ''' <remarks>To help with cloning.</remarks>
        Public Sub New()
            MyBase.New(RequiredCharacterRule._runtimeTypeHandle, Nothing, _
                       False)
            _requiredCharacter = RequiredCharacter
        End Sub

        ''' <summary>
        ''' Initialize a new instance of the <see cref="RequiredCharacterRule"/> class.
        ''' </summary>
        ''' <param name="errorMessage">The custom error message to use. Pass a null to 
        ''' use the default value.</param>
        ''' <param name="requiredCharacter">The invalid character.</param>
        Public Sub New(ByVal errorMessage As String, _
                       ByVal useErrorMessageProvider As Boolean, ByVal requiredCharacter As Char)
            MyBase.New(RequiredCharacterRule._runtimeTypeHandle, errorMessage, _
                       useErrorMessageProvider)
            _requiredCharacter = requiredCharacter
        End Sub


        ''' <summary>
        ''' Called after the <see cref="Rule"/> is added to a <see cref="RuleCollection"/>.
        ''' <see cref="Rule.ErrorMessage"/> is null.
        ''' </summary>
        ''' <returns>The error message for the <see cref="Rule"/>.</returns>
        ''' <param name="tokenizedMemberName">A user friendly representation of the 
        ''' member name.</param>
        ''' <param name="descriptorType">
        ''' If <see cref="InfoDescriptor"/> is a <see cref="PropertyDescriptor"/> then <paramref name="descriptorType"/> will be 'property'.
        ''' If <see cref="InfoDescriptor"/> is a <see cref="ParameterDescriptor"/> then <paramref name="descriptorType"/> will be 'parameter'.
        ''' </param>
        Protected Overrides Function GetComputedErrorMessage(ByVal tokenizedMemberName As _
                                                                String, ByVal descriptorType As _
                                                                String) As String
            Return String.Format("The {0} '{1}' must contain the character '{2}'", _
                                 descriptorType, tokenizedMemberName, RequiredCharacter)
        End Function


        ''' <summary>
        ''' Checks if the current <see cref="Rule"/> is equivalent to another 
        ''' <see cref="Rule"/>.
        ''' </summary>
        ''' <remarks>
        ''' Called for each <see cref="Rule"/> in <see cref="RuleCollection"/> when a new 
        ''' <see cref="Rule"/> is added. This method is only called when both the existing 
        ''' <see cref="Rule"/> and the <see cref="Rule"/> being are of the same 
        ''' <see cref="Type"/> and have the same RuleSet. So it is safe to 
        ''' directly cast <paramref name="rule"/> to the current type. All properties in 
        ''' <paramref name="rule"/> should be compared to the propeties of the current 
        ''' <see cref="Rule"/>.
        ''' </remarks>
        ''' <param name="rule">The <see cref="Rule"/> to check for equivalence.</param>
        ''' <returns><see langword="true"/> if <paramref name="rule"/> is equivalent to the 
        ''' current <see cref="Rule"/>; otherwise <see langword="false"/>.</returns>
        Public Overrides Function IsEquivalent(ByVal rule As Rule) As Boolean
            Dim requiredCharacterRule As RequiredCharacterRule = DirectCast(rule,  _
                    RequiredCharacterRule)
            Return (RequiredCharacter = requiredCharacterRule.RequiredCharacter)
        End Function

        ''' <summary>
        ''' Validate the member this <see cref="Rule"/> is applied to.
        ''' </summary>
        ''' <param name="targetObjectValue">The value of the object containing the member to 
        ''' validate.</param>
        ''' <param name="context">An <see cref="object"/> that contains data for the 
        ''' <see cref="Rule"/> to validate. The default is null.</param>
        ''' <param name="targetMemberValue">The value of the member to validate.</param>
        Public Overrides Function Validate(ByVal targetObjectValue As Object, ByVal targetMemberValue As Object, ByVal context As Object, ByVal infoDescriptor As InfoDescriptor) As ValidationResult
            If (Not targetMemberValue Is Nothing) Then
                Dim valueAsString As String = CStr(targetMemberValue)
                If (valueAsString.IndexOf(RequiredCharacter) = -1) Then
                    Return New ValidationResult(Me, MyBase.ErrorMessage, targetMemberValue, infoDescriptor)
                End If
            End If
            Return Nothing
        End Function



        ' Properties
        ''' <summary>
        ''' Gets the required character.
        ''' </summary>
        Public ReadOnly Property RequiredCharacter() As Char
            Get
                Return _requiredCharacter
            End Get
        End Property

        ''' <summary>
        ''' Gets a <see cref="string"/> that is a business interpretation of the 
        ''' <see cref="Rule"/>.
        ''' </summary>
        Public Overrides ReadOnly Property RuleInterpretation() As String
            Get
                Return String.Format("The value must contain the character '{0}'", _
                                     RequiredCharacter)
            End Get
        End Property


        ' Fields
        Private _requiredCharacter As Char

        '' RequiredCharacterRule can only be applied to strings. So pass the 
        '' <see cref="RuntimeTypeHandle"/> for string to the base constructor.
        Private Shared _runtimeTypeHandle As RuntimeTypeHandle = GetType(String).TypeHandle
    End Class
End Namespace